package com.yuhan.common.base;

import com.yuhan.common.utils.Page;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @program: yunpi-credit-parent
 * @description: 分页实现
 * @author: hejing
 * @create: 2019-08-03 14:36
 **/
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>  implements BaseRepository<T, ID> {

    //实体管理类，对持久化实体做增删改查，自动义sq操作模板所需要的核心类
    public final EntityManager entityManager;
    public final JpaEntityInformation<T, ID> entityInformation;

    public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityInformation = entityInformation;
        this.entityManager = entityManager;
    }

    @Override
    @Transactional
    public <S extends T> S save(S entity) {
        if (entityInformation.isNew(entity)) {
            entityManager.persist(entity);
            return entity;
        } else {
            DynamicUpdate dynamicUpdateValue = entity.getClass().getAnnotation(DynamicUpdate.class);
            //如果有动态更新的注解,并且值是true，那么动态更新
            if (dynamicUpdateValue != null && dynamicUpdateValue.value()) {
                //获取ID
                ID entityId = (ID) entityInformation.getId(entity);
                //查询数据库数据
                T dataFromDb = findById(entityId).get();
                //获取为空的属性-覆盖的时候忽略
                String[] ignoreProperties = getNotNullProperties(entity);
                //用数据库对象对应的信息覆盖实体中属性为null的信息
                BeanUtils.copyProperties(dataFromDb, entity, ignoreProperties);
            }
            //更新
            return entityManager.merge(entity);
        }
    }

    /**
     * 获取对象的不为null的属性
     */
    private static String[] getNotNullProperties(Object src) {
        //1.获取Bean
        BeanWrapper srcBean = new BeanWrapperImpl(src);
        //2.获取Bean的属性描述
        PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();
        //3.获取Bean的空属性
        Set<String> properties = new HashSet<>();
        for (PropertyDescriptor propertyDescriptor : pds) {
            String propertyName = propertyDescriptor.getName();
            Object propertyValue = srcBean.getPropertyValue(propertyName);
            if (propertyValue != null) {
                properties.add(propertyName);
            }
        }
        return properties.toArray(new String[0]);
    }

    public List<T> findAll(Page page, String hql) {
        Query query = entityManager.createQuery(hql);
        if (page != null) {
            // 分页
            Long totalCount = (long) query.getResultList().size();
            page.setTotal(totalCount);
            // firstResult的序号从0开始
            query.setFirstResult(page.getFirst());
            if (page.getPageSize() != -1) {
                query.setMaxResults(page.getPageSize());
            }
        }
        return query.getResultList();
    }

    public List<T> findAll(Page page, String sql, Class<T> clazz) {
        sql = sql.toLowerCase();
        if (page != null) {
            String countsql = "select count(1) " + sql.substring(sql.indexOf("from"), sql.length());
            Query countQuery = entityManager.createNativeQuery(countsql);
            Integer count = ((BigInteger) countQuery.getSingleResult()).intValue();
            page.setTotal(count);
            sql += " limit " + page.getFirst() + "," + page.getPageSize();
        }
        Query query = entityManager.createNativeQuery(sql, clazz);
        List<T> list = query.getResultList();
        return list;
    }

    @Override
    public List<Map> findMap(Page page, String hql) {
        hql = hql.toLowerCase();
        if (page != null) {
            String countsql = "select count(1) " + hql.substring(hql.indexOf("from"), hql.length());
            Query countQuery = entityManager.createNativeQuery(countsql);
            Integer count = ((BigInteger) countQuery.getSingleResult()).intValue();
            page.setTotal(count);
            hql += " limit " + page.getFirst() + "," + page.getPageSize();
        }
        Query query = entityManager.createNativeQuery(hql);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return query.getResultList();
    }
}
